home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / histogram_tool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-15  |  13.0 KB  |  467 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18. #include "config.h"
  19.  
  20. #include <glib.h>
  21.  
  22. #include "apptypes.h"
  23.  
  24. #include "appenv.h"
  25. #include "drawable.h"
  26. #include "gdisplay.h"
  27. #include "gimpui.h"
  28. #include "histogram_tool.h"
  29.  
  30. #include "libgimp/gimpintl.h"
  31. #include "libgimp/gimpmath.h"
  32.  
  33. #define TEXT_WIDTH       45
  34. #define GRADIENT_HEIGHT  15
  35.  
  36. /*  the histogram structures  */
  37.  
  38. typedef struct _HistogramTool HistogramTool;
  39.  
  40. struct _HistogramTool
  41. {
  42.   gint x, y;   /*  coords for last mouse click  */
  43. };
  44.  
  45. /*  the histogram tool options  */
  46. static ToolOptions * histogram_tool_options = NULL;
  47.  
  48. /*  the histogram tool dialog  */
  49. static HistogramToolDialog * histogram_tool_dialog = NULL;
  50.  
  51. /*  histogram_tool action functions  */
  52. static void   histogram_tool_control (Tool *, ToolAction, gpointer);
  53.  
  54. static HistogramToolDialog *  histogram_tool_dialog_new (void);
  55.  
  56. static void   histogram_tool_close_callback   (GtkWidget *, gpointer);
  57. static void   histogram_tool_channel_callback (GtkWidget *, gpointer);
  58. static void   histogram_tool_gradient_draw    (GtkWidget *, gint);
  59.  
  60. static void   histogram_tool_dialog_update    (HistogramToolDialog *,
  61.                            gint, gint);
  62.  
  63. /*  histogram_tool machinery  */
  64.  
  65. void
  66. histogram_tool_histogram_range (HistogramWidget *widget,
  67.                 gint             start,
  68.                 gint             end,
  69.                 gpointer         data)
  70. {
  71.   HistogramToolDialog *htd;
  72.   gdouble pixels;
  73.   gdouble count;
  74.  
  75.   htd = (HistogramToolDialog *) data;
  76.  
  77.   if (htd == NULL || htd->hist == NULL ||
  78.       gimp_histogram_nchannels(htd->hist) <= 0)
  79.     return;
  80.  
  81.   pixels = gimp_histogram_get_count (htd->hist, 0, 255);
  82.   count  = gimp_histogram_get_count (htd->hist, start, end);
  83.  
  84.   htd->mean       = gimp_histogram_get_mean (htd->hist, htd->channel,
  85.                          start, end);
  86.   htd->std_dev    = gimp_histogram_get_std_dev (htd->hist, htd->channel,
  87.                         start, end);
  88.   htd->median     = gimp_histogram_get_median (htd->hist, htd->channel,
  89.                            start, end);
  90.   htd->pixels     = pixels;
  91.   htd->count      = count;
  92.   htd->percentile = count / pixels;
  93.  
  94.   if (htd->shell)
  95.     histogram_tool_dialog_update (htd, start, end);
  96. }
  97.  
  98. static void
  99. histogram_tool_dialog_update (HistogramToolDialog *htd,
  100.                   gint                 start,
  101.                   gint                 end)
  102. {
  103.   gchar text[12];
  104.  
  105.   /*  mean  */
  106.   g_snprintf (text, sizeof (text), "%3.1f", htd->mean);
  107.   gtk_label_set_text (GTK_LABEL (htd->info_labels[0]), text);
  108.  
  109.   /*  std dev  */
  110.   g_snprintf (text, sizeof (text), "%3.1f", htd->std_dev);
  111.   gtk_label_set_text (GTK_LABEL (htd->info_labels[1]), text);
  112.  
  113.   /*  median  */
  114.   g_snprintf (text, sizeof (text), "%3.1f", htd->median);
  115.   gtk_label_set_text (GTK_LABEL (htd->info_labels[2]), text);
  116.  
  117.   /*  pixels  */
  118.   g_snprintf (text, sizeof (text), "%8.1f", htd->pixels);
  119.   gtk_label_set_text (GTK_LABEL (htd->info_labels[3]), text);
  120.  
  121.   /*  intensity  */
  122.   if (start == end)
  123.     g_snprintf (text, sizeof (text), "%d", start);
  124.   else
  125.     g_snprintf (text, sizeof (text), "%d..%d", start, end);
  126.   gtk_label_set_text (GTK_LABEL (htd->info_labels[4]), text);
  127.  
  128.   /*  count  */
  129.   g_snprintf (text, sizeof (text), "%8.1f", htd->count);
  130.   gtk_label_set_text (GTK_LABEL (htd->info_labels[5]), text);
  131.  
  132.   /*  percentile  */
  133.   g_snprintf (text, sizeof (text), "%2.2f", htd->percentile * 100);
  134.   gtk_label_set_text (GTK_LABEL (htd->info_labels[6]), text);
  135. }
  136.  
  137. /*  histogram_tool action functions  */
  138.  
  139. static void
  140. histogram_tool_control (Tool       *tool,
  141.             ToolAction  action,
  142.             gpointer    gdisp_ptr)
  143. {
  144.   switch (action)
  145.     {
  146.     case PAUSE:
  147.       break;
  148.  
  149.     case RESUME:
  150.       break;
  151.  
  152.     case HALT:
  153.       if (histogram_tool_dialog)
  154.     histogram_tool_close_callback (NULL, (gpointer) histogram_tool_dialog);
  155.       break;
  156.  
  157.     default:
  158.       break;
  159.     }
  160. }
  161.  
  162. Tool *
  163. tools_new_histogram_tool (void)
  164. {
  165.   Tool * tool;
  166.   HistogramTool * private;
  167.  
  168.   /*  The tool options  */
  169.   if (! histogram_tool_options)
  170.     {
  171.       histogram_tool_options = tool_options_new (_("Histogram"));
  172.       tools_register (HISTOGRAM, histogram_tool_options);
  173.     }
  174.  
  175.   tool = tools_new_tool (HISTOGRAM);
  176.   private = g_new0 (HistogramTool, 1);
  177.  
  178.   tool->scroll_lock = TRUE;   /*  Disallow scrolling  */
  179.   tool->preserve    = FALSE;  /*  Don't preserve on drawable change  */
  180.  
  181.   tool->private = (void *) private;
  182.  
  183.   tool->control_func = histogram_tool_control;
  184.  
  185.   return tool;
  186. }
  187.  
  188. void
  189. tools_free_histogram_tool (Tool *tool)
  190. {
  191.   HistogramTool * hist;
  192.  
  193.   hist = (HistogramTool *) tool->private;
  194.  
  195.   /*  Close the histogram dialog  */
  196.   if (histogram_tool_dialog)
  197.     histogram_tool_close_callback (NULL, (gpointer) histogram_tool_dialog);
  198.  
  199.   g_free (hist);
  200. }
  201.  
  202. void
  203. histogram_tool_initialize (GDisplay *gdisp)
  204. {
  205.   PixelRegion PR;
  206.  
  207.   if (drawable_indexed (gimage_active_drawable (gdisp->gimage)))
  208.     {
  209.       g_message (_("Histogram does not operate on indexed drawables."));
  210.       return;
  211.     }
  212.  
  213.   /*  The histogram_tool dialog  */
  214.   if (!histogram_tool_dialog)
  215.     histogram_tool_dialog = histogram_tool_dialog_new ();
  216.   else if (!GTK_WIDGET_VISIBLE (histogram_tool_dialog->shell))
  217.     gtk_widget_show (histogram_tool_dialog->shell);
  218.  
  219.   histogram_tool_dialog->drawable = gimage_active_drawable (gdisp->gimage);
  220.   histogram_tool_dialog->color = drawable_color (histogram_tool_dialog->drawable);
  221.  
  222.   /*  hide or show the channel menu based on image type  */
  223.   if (histogram_tool_dialog->color)
  224.     gtk_widget_show (histogram_tool_dialog->channel_menu);
  225.   else
  226.     {
  227.       /* Channels can only have value histograms; reconfigure channel menu. */
  228.       /* Note: gimp_histogram_get_mean() in gimphistogram.c. garo 5/7/2001  */ 
  229.       histogram_tool_dialog->channel = GIMP_HISTOGRAM_VALUE;
  230.       gimp_option_menu_set_history (g_list_nth_data 
  231.                     (gtk_container_children 
  232.                      (GTK_CONTAINER 
  233.                       (histogram_tool_dialog->channel_menu)), 
  234.                      1), 
  235.                     GINT_TO_POINTER (GIMP_HISTOGRAM_VALUE));
  236.       gtk_widget_hide (histogram_tool_dialog->channel_menu);
  237.       histogram_tool_gradient_draw (histogram_tool_dialog->gradient, 
  238.                     GIMP_HISTOGRAM_VALUE);
  239.     }
  240.  
  241.   /* calculate the histogram */
  242.   pixel_region_init (&PR, drawable_data (histogram_tool_dialog->drawable), 0, 0,
  243.              drawable_width (histogram_tool_dialog->drawable),
  244.              drawable_height (histogram_tool_dialog->drawable),
  245.              FALSE);
  246.   gimp_histogram_calculate (histogram_tool_dialog->hist, &PR, NULL);
  247.  
  248.   histogram_widget_update (histogram_tool_dialog->histogram,
  249.                histogram_tool_dialog->hist);
  250.   histogram_widget_range (histogram_tool_dialog->histogram, 0, 255);
  251. }
  252.  
  253. /***************************/
  254. /*  Histogram Tool dialog  */
  255. /***************************/
  256.  
  257. static HistogramToolDialog *
  258. histogram_tool_dialog_new (void)
  259. {
  260.   HistogramToolDialog *htd;
  261.   GtkWidget *main_vbox;
  262.   GtkWidget *hbox;
  263.   GtkWidget *vbox;
  264.   GtkWidget *grad_hbox;
  265.   GtkWidget *frame;
  266.   GtkWidget *table;
  267.   GtkWidget *label;
  268.   GtkWidget *option_menu;
  269.   gint i;
  270.   gint x, y;
  271.  
  272.   static gchar * histogram_info_names[] =
  273.   {
  274.     N_("Mean:"),
  275.     N_("Std Dev:"),
  276.     N_("Median:"),
  277.     N_("Pixels:"),
  278.     N_("Intensity:"),
  279.     N_("Count:"),
  280.     N_("Percentile:")
  281.   };
  282.  
  283.   htd = g_new (HistogramToolDialog, 1);
  284.   htd->channel = GIMP_HISTOGRAM_VALUE;
  285.   htd->hist    = gimp_histogram_new ();
  286.  
  287.   /*  The shell and main vbox  */
  288.   htd->shell = gimp_dialog_new (_("Histogram"), "histogram",
  289.                 tools_help_func,
  290.                 tool_info[HISTOGRAM].private_tip,
  291.                 GTK_WIN_POS_NONE,
  292.                 FALSE, TRUE, FALSE,
  293.  
  294.                 _("Close"), histogram_tool_close_callback,
  295.                 htd, NULL, NULL, TRUE, TRUE,
  296.  
  297.                 NULL);
  298.  
  299.   main_vbox = gtk_vbox_new (FALSE, 4);
  300.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 4);
  301.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (htd->shell)->vbox), main_vbox);
  302.  
  303.   hbox = gtk_hbox_new (TRUE, 0);
  304.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  305.  
  306.   vbox = gtk_vbox_new (FALSE, 4);
  307.   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
  308.  
  309.   /*  The option menu for selecting channels  */
  310.   htd->channel_menu = gtk_hbox_new (FALSE, 6);
  311.   gtk_box_pack_start (GTK_BOX (vbox), htd->channel_menu, FALSE, FALSE, 0);
  312.  
  313.   label = gtk_label_new (_("Information on Channel:"));
  314.   gtk_box_pack_start (GTK_BOX (htd->channel_menu), label, FALSE, FALSE, 0);
  315.   gtk_widget_show (label);
  316.  
  317.   option_menu = gimp_option_menu_new2
  318.     (FALSE, histogram_tool_channel_callback,
  319.      htd, GINT_TO_POINTER (htd->channel),
  320.  
  321.      _("Value"), GINT_TO_POINTER (GIMP_HISTOGRAM_VALUE), NULL,
  322.      _("Red"),   GINT_TO_POINTER (GIMP_HISTOGRAM_RED),   NULL,
  323.      _("Green"), GINT_TO_POINTER (GIMP_HISTOGRAM_GREEN), NULL,
  324.      _("Blue"),  GINT_TO_POINTER (GIMP_HISTOGRAM_BLUE),  NULL,
  325.  
  326.      NULL);
  327.   gtk_box_pack_start (GTK_BOX (htd->channel_menu), option_menu, FALSE, FALSE, 0);
  328.   gtk_widget_show (option_menu);
  329.  
  330.   gtk_widget_show (htd->channel_menu);
  331.  
  332.   /*  The histogram tool histogram  */
  333.   frame = gtk_frame_new (NULL);
  334.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  335.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  336.  
  337.   htd->histogram = histogram_widget_new (HISTOGRAM_WIDTH, HISTOGRAM_HEIGHT);
  338.   gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET(htd->histogram));
  339.  
  340.   gtk_signal_connect (GTK_OBJECT (htd->histogram), "range_changed",
  341.               GTK_SIGNAL_FUNC (histogram_tool_histogram_range),
  342.               htd);
  343.  
  344.   gtk_widget_show (GTK_WIDGET (htd->histogram));
  345.   gtk_widget_show (frame);
  346.  
  347.   /*  The gradient below the histogram */
  348.   grad_hbox = gtk_hbox_new (TRUE, 0);
  349.   gtk_box_pack_start (GTK_BOX (vbox), grad_hbox, FALSE, FALSE, 0);
  350.   frame = gtk_frame_new (NULL);
  351.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  352.   gtk_box_pack_start (GTK_BOX (grad_hbox), frame, FALSE, FALSE, 0);
  353.  
  354.   htd->gradient = gtk_preview_new (GTK_PREVIEW_COLOR);
  355.   gtk_preview_size (GTK_PREVIEW (htd->gradient), 
  356.             HISTOGRAM_WIDTH, GRADIENT_HEIGHT);
  357.   gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET(htd->gradient));
  358.   gtk_widget_show (htd->gradient);
  359.   gtk_widget_show (frame);
  360.   gtk_widget_show (grad_hbox);
  361.   histogram_tool_gradient_draw (htd->gradient, GIMP_HISTOGRAM_VALUE);
  362.  
  363.   gtk_widget_show (vbox);
  364.   gtk_widget_show (hbox);
  365.  
  366.   /*  The table containing histogram information  */
  367.   table = gtk_table_new (4, 4, TRUE);
  368.   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
  369.   gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
  370.  
  371.   /*  the labels for histogram information  */
  372.   for (i = 0; i < 7; i++)
  373.     {
  374.       y = (i % 4);
  375.       x = (i / 4) * 2;
  376.  
  377.       label = gtk_label_new (gettext(histogram_info_names[i]));
  378.       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  379.       gtk_table_attach (GTK_TABLE (table), label, x, x + 1, y, y + 1,
  380.             GTK_FILL, GTK_FILL, 2, 2);
  381.       gtk_widget_show (label);
  382.  
  383.       htd->info_labels[i] = gtk_label_new ("0");
  384.       gtk_misc_set_alignment (GTK_MISC (htd->info_labels[i]), 0.0, 0.5);
  385.       gtk_table_attach (GTK_TABLE (table), htd->info_labels[i],
  386.             x + 1, x + 2, y, y + 1,
  387.             GTK_FILL, GTK_FILL, 2, 2);
  388.       gtk_widget_show (htd->info_labels[i]);
  389.     }
  390.  
  391.   gtk_widget_show (table);
  392.  
  393.   gtk_widget_show (main_vbox);
  394.   gtk_widget_show (htd->shell);
  395.  
  396.   return htd;
  397. }
  398.  
  399. static void
  400. histogram_tool_close_callback (GtkWidget *widget,
  401.                    gpointer   data)
  402. {
  403.   HistogramToolDialog *htd;
  404.  
  405.   htd = (HistogramToolDialog *) data;
  406.  
  407.   gimp_dialog_hide (htd->shell);
  408.        
  409.   active_tool->gdisp_ptr = NULL;
  410.   active_tool->drawable = NULL;
  411. }
  412.  
  413. static void
  414. histogram_tool_channel_callback (GtkWidget *widget,
  415.                  gpointer   data)
  416. {
  417.   HistogramToolDialog *htd;
  418.  
  419.   htd = (HistogramToolDialog *) data;
  420.  
  421.   gimp_menu_item_update (widget, &htd->channel);
  422.  
  423.   histogram_widget_channel (htd->histogram, htd->channel);
  424.   histogram_tool_gradient_draw (htd->gradient, htd->channel);
  425. }
  426.  
  427. static void
  428. histogram_tool_gradient_draw (GtkWidget *gradient,
  429.                   gint       channel)
  430. {
  431.   guchar buf[HISTOGRAM_WIDTH * 3];
  432.   guchar r, g, b;
  433.   gint i;
  434.  
  435.   r = g = b = 0;
  436.   switch (channel)
  437.     {
  438.     case GIMP_HISTOGRAM_VALUE:
  439.     case GIMP_HISTOGRAM_ALPHA:  r = g = b = 1;
  440.       break;
  441.     case GIMP_HISTOGRAM_RED:    r = 1;
  442.       break;
  443.     case GIMP_HISTOGRAM_GREEN:  g = 1;
  444.       break;
  445.     case GIMP_HISTOGRAM_BLUE:   b = 1;
  446.       break;
  447.     default:
  448.       g_warning ("unknown channel type, can't happen\n");
  449.       break;
  450.     }
  451.   
  452.   for (i = 0; i < HISTOGRAM_WIDTH; i++)
  453.     {
  454.       buf[3*i+0] = i*r;
  455.       buf[3*i+1] = i*g;
  456.       buf[3*i+2] = i*b;
  457.     }
  458.  
  459.   for (i = 0; i < GRADIENT_HEIGHT; i++)
  460.     gtk_preview_draw_row (GTK_PREVIEW (gradient),
  461.               buf, 0, i, HISTOGRAM_WIDTH);
  462.   
  463.   gtk_widget_queue_draw (gradient);
  464. }
  465.  
  466.  
  467.